package com.whut.monitor.netty;

import com.whut.monitor.netty.handler.KeepAliveHeartFilter;
import com.whut.monitor.netty.handler.ModelUpdateInboundHandler;
import com.whut.monitor.netty.handler.ServerInboundHandler;
import com.whut.monitor.netty.handler.SyncDataHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleStateHandler;
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;

/**
 * @author qing
 * Netty配置，用于和机床现场设备通信
 */
@Component
public class NettyServer implements ApplicationListener {

    private static final Logger logger = Logger.getLogger(NettyServer.class);

    // TCP端口号
    private static final int PORT = 3690;

    private static ServerBootstrap bootstrap = null;
    private static EventLoopGroup bossGroup = null;
    private static EventLoopGroup workerGroup = null;

    @Resource(name = "ServerInboundHandler")
    private ServerInboundHandler serverInboundHandler;
    @Resource(name="SyncDataHandler")
    private SyncDataHandler syncDataHandler;
    @Resource(name="ModelUpdateInboundHandler")
    private ModelUpdateInboundHandler modelUpdateInboundHandler;

    private synchronized void start() {
        if (isAccepting()) {
            logger.info("NETTY SERVER IS ALREADY STARTED!");
            return;
        }
        try {
            bootstrap = new ServerBootstrap();
            bossGroup = new NioEventLoopGroup();
            workerGroup = new NioEventLoopGroup();
            bootstrap.group(bossGroup, workerGroup);
            bootstrap.channel(NioServerSocketChannel.class);
            bootstrap.option(ChannelOption.SO_BACKLOG, 128);
            // 通过NoDelay禁用Nagle,使消息立即发出去，不用等待到一定的数据量才发出去
            bootstrap.option(ChannelOption.TCP_NODELAY, true);
            // 保持长连接状态
            bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
            bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    ChannelPipeline p = socketChannel.pipeline();
                    p.addLast("timeout", new IdleStateHandler(60, 120, 120, TimeUnit.SECONDS));
                    //Tcp分组发送
                    // 根据自定义分隔符组合成完整的包
                    ByteBuf delimiter = Unpooled.copiedBuffer("end\n".getBytes());
                    //增大缓冲区间大小 512MB
                    p.addLast("package", new DelimiterBasedFrameDecoder(512*1024*1024, delimiter));
                    //Tcp分组发送，根据换行符组合成完整的包
//                    p.addLast("package",new LineBasedFrameDecoder(2048*2));
//                    p.addLast("package",new LengthFieldBasedFrameDecoder(1024*1024*1024, 0, 4,0,4)); 
                    // 设置编解码器
                    p.addLast("encoder", new StringEncoder(Charset.forName("UTF-8")));
                    p.addLast("decoder", new StringDecoder(Charset.forName("UTF-8")));
                    // 心跳机制
//                    p.addLast("heart", new KeepAliveHeartFilter());
                    //设置处理类
                    //先判断是否大于50个字节，若小于50个字节，则由modelUpdateInboundHandler处理；
                    //若大于50个字节，则传递给syncDataHandler
                    //若发现msg中第二段有“HbaseCP”字符串，则由syncDataHandler处理，
                    //若无“HbaseCP”字符串，则传递给serverInboundHandler
                    p.addLast("handler1", modelUpdateInboundHandler);
                    p.addLast("handler2", syncDataHandler);
                    p.addLast("handler3", serverInboundHandler);
                }
            });
            // 服务端绑定端口
            ChannelFuture future = bootstrap.bind(PORT).sync();
            if (future.isSuccess()) {
                logger.info("NETTY SERVER IS STARTED!");
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.info("NETTY SERVER START FAILED!");
            ServerInboundHandler.closeChannels();
            // TODO
            //这里不知道该关闭哪个Handler,需完善！！！
            close();
        }
    }


    private static boolean isAccepting() {
        return bootstrap != null && !bossGroup.isShutdown() && !workerGroup.isShutdown();
    }

    private synchronized void close() {
        // 关闭Netty
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
        // 先显式得设为null
        bootstrap = null;
        logger.info("NETTY SERVER CLOSED!");
        logger.info("NETTY IS ACCEPTING=" + isAccepting());
    }

//  public static void main(String[] args) throws InterruptedException {
//        final NettyServer server = new NettyServer();
//        server.start();
//        new Thread(new Runnable() {
//            @Override
//            public void run() {
//                try {
//                    Thread.sleep(10000);
//                    server.close();
//                    Thread.sleep(10000);
//                    server.start();
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//
//            }
//        }).start();
//    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ContextRefreshedEvent && ((ContextRefreshedEvent) event).getApplicationContext().getParent() == null) {
            start();
        } else if (event instanceof ContextClosedEvent) {
            close();
        }
    }

}
